/*
The surface-physics project: http://code.google.com/p/surface-physics/
Adds real world physics based on the Bullet physics engine, to bases in the Orbiter space
flight simulation software.

Written by Abhijit Nandy
License : Apache License 2.0

Bump_BulletBase.h
BulletBase management directly from within Bump. Objects of this class are created
in the Bump module and uses a BulletBase VESSEL as a proxy for inserting meshes and attaching
objects. The BulletBase has no other role other than key forwarding (as of now) which is
difficult to do from a module. This class merges Orbiter and Bullet functionality towards
achieving the above outlined purpose.

This is possible due to the extensive public API of VESSEL & its derived classes.

This file declares the interface for the Bump_BulletBase class. Its role:
1. Creates the BulletBase proxy VESSEL at the location of the passed base
2. Reads the base specific physics file and staggers creation of objects in update()
   which is called at every sim step.
3. Reads command from a BulletBase public member and passes it on to components/attachments or
	processes them itself as reqd.
4. Scans the sky for nearby objects and attaches/detaches them as needed(does not scan in every step)


Do not store any global positions, or any positions, always get them again when needed(they all change)
OBJHANDLEs can be stored like handle to base or reference body. These wont change.


*/


#pragma once

#include "orbitersdk.h"
#include "BulletBase.h"

#include "../ThreadSupport/Bump_Thread.h"

#include <list>
#include <unordered_map>



#include "btBulletDynamicsCommon.h"

#define MAX_OBJECTS 10
#define MAX_STRLEN 50

//Useful macros
#define V3ARGS(a)	(a).x, (a).y, (a).z

class Bump_BaseObject;
class Bump_TerrainPatch;


/**
 * Based on last action, a FSM based on Orbiter's time step
 * Used for gradual loading of objects into the simulation
 */
static enum BaseMode
{
	IDLE,
	CREATED_BB,
	CHECKED_TERRAIN_GEN,
	OPENED_FILE,	//loading of objects in this state till end of physics file
	INITIAL_LANDED_PASS,
	PARSED_FILE		//Normal running mode after all objects loaded
};


//This map stores a list of struct BaseObject*, NOT Bump_BaseObject
typedef std::list<Bump_BaseObject*> BaseObjectList;

typedef std::tr1::unordered_map<OBJHANDLE, Bump_BaseObject*> BaseObjectMap;//Orbiter-Bump object map


/**
 * The Bump_BulletBase to create and manage a BulletBase
 */
class Bump_BulletBase : public Bump_ThreadTargetInterface
{
//#pragma message("Bump_BulletBase.h included")
	char output[1000];
	
	//Offset of this base in physics world
	btVector3 physicsWorldOffset;

	//Section cutoff point : should there be section specific cutoffs read from file ?
	double cutoff;

	const double MAX_TERRAIN_ELEVATION;

	//Supporting terrain for base, individual objects generate ground only beyond the base's range
	Bump_TerrainPatch *ground;



	//Physics file
	FILEHANDLE physicsFile;

	//Physics file reading utilities
	void	readPhysicsFileDescription(void);
	void	readCreatePhysicsFileObject(void);

	//Objects factory based object creation
	int 	createTypedBaseObject(char *strType, char *strObjName, OBJHANDLE hObj = NULL);

	//Switch-case based object creation
	int 	createBaseObject(char *strType, char *strObjName, char *line);

	//Ranging pass to get distances of vessels from base
	void 	rangingPass(bool skipLanded);

	bool	checkAttachments(VESSEL3 *v);

	int		printControlMap(void);
	int		printObjectList(void);

	
public:

	//Base Name
	char strBaseName[MAX_STRLEN];

	//Latitude, longitude, radius of proxy base vessel: may not match ref body if base above surface
	double lng, lat, rad;

	//Mass of this base
	double mass;

	//Handle to Orbiter base if one exists(not the BulletBase), e.g. Moon for Brighton Beach.
	OBJHANDLE hObjBase;

	//Handle to reference body OBJECT
	OBJHANDLE hObjRefBody;

	//Radius if reference body (rad >= radRefBody)
	double radRefBody;

	//Gravitational force of reference body
	VECTOR3 G;

	//Pointers to associated BulletBase, to read commands from it
	OBJHANDLE hObjBulletBase;
	VESSEL3 *vBulletBase;
	BulletBase *bb;

	//Used to track loads of objects
	BaseMode mode;

	//Objects managed by this base
	BaseObjectList baseObjList;
	BaseObjectList::iterator objIter;

	//Unordered map using hashes for keeping controlled VESSELs to skip against
	BaseObjectMap objMap;
	BaseObjectMap::iterator objMapIter;

	//Physics stuff, dynamics world maintained by Bump ? Or base ?
	btDynamicsWorld *m_dynamicsWorld;

	//General Physics world variables
	btAlignedObjectArray<btCollisionShape*> *m_collisionShapes;

	static const int BULLET_WORLD_SIZE = 10000;

	//True if this base uses a terrain generator
	bool terrainGenerationEnabled;
	double maxTerrainRadialDist, maxTerrainElevation;

	//Sim stuff
	static unsigned long simStep;
	static double SimT, SimDT, MJD;

	volatile long count;


	Bump_BulletBase();
	virtual ~Bump_BulletBase();

	//Main base management functions
	int		init(OBJHANDLE hObj, OBJHANDLE hObjRBody);
	int		prestep(double SimT, double SimDT, double MJD);
	int		poststep(double SimT, double SimDT, double MJD);
	int		exit();


	//Multithreading suport
	int		run();

	

	//Physics rigid body creation
	btRigidBody*	localCreateRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape);

	//Section update
	void	refreshSections(void);

	//Forced drop of objects by 3rd party(1st party is base, 2nd is baseobject, 3rd is some external object)
	int		dropBaseObject(OBJHANDLE hObjDrop);


	void 	setDynamicsWorld(btDynamicsWorld* dynamicsWorld)
	{ m_dynamicsWorld = dynamicsWorld; }

	void 	setCollisionShapesArray(btAlignedObjectArray<btCollisionShape*> *collisionShapes)
	{ m_collisionShapes = collisionShapes; }
};





